package com.spa.infrastructure.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.google.common.collect.Lists;
import com.spa.application.dto.member.MemberAppointmentTimeDTO;
import com.spa.application.dto.member.MemberAppointmentTimeListDTO;
import com.spa.domain.entity.OrderExt;
import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class OrderUtils {

    /**
     * 计算订单总价
     *
     * @param servicePrice    项目金额
     * @param serviceQuantity 项目数量
     * @param couponPrice     优惠券金额
     * @author: lig
     * @date: 2023/12/13
     */
    public static Integer calcOrderTotal(Integer servicePrice, Integer serviceQuantity, Integer couponPrice,
                                   Double travelPrice) {
        BigDecimal servicePriceDec = BigDecimal.valueOf(servicePrice);
        servicePriceDec = servicePriceDec.multiply(BigDecimal.valueOf(serviceQuantity));
        if (ObjectUtils.isNotEmpty(couponPrice)) {
            servicePriceDec = servicePriceDec.subtract(BigDecimal.valueOf(couponPrice));
        }
        if (ObjectUtils.isNotEmpty(travelPrice)) {
            servicePriceDec = servicePriceDec.add(BigDecimal.valueOf(travelPrice));
        }
        return servicePriceDec.intValue();
    }


    /**
     * 计算订单项目金额   项目 * 数量
     *
     * @author: lig
     * @date: 2023/12/13
     */
    public static Integer calcOrderServiceTotal(Integer servicePrice, Integer serviceQuantity) {
        Integer total = (servicePrice * serviceQuantity);
        return total;
    }


    /**
     * 生成订单编号  22位
     *
     * @author: lig
     * @date: 2023-12-20
     */
    public static String generateOrderCode() {
        String prefix = "DD";
        String prefixRandom = Convert.toStr(RandomUtil.randomNumbers(2));
        String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = Convert.toStr(RandomUtil.randomInt(3));

        StringBuffer orderCode = new StringBuffer();
        orderCode.append(prefix);
        orderCode.append(prefixRandom);
        orderCode.append(dateTime);
        orderCode.append(random);

        return orderCode.toString();

    }

    /**
     * 生成扩展订单编号   22位
     *
     * @author: lig
     * @date: 2023-12-20
     */
    public static String generateExtOrderCode() {
        String prefix = "EXT";
        String prefixRandom = RandomUtil.randomNumbers(2);
        String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = RandomUtil.randomNumbers(2);

        StringBuffer orderCode = new StringBuffer();
        orderCode.append(prefix);
        orderCode.append(prefixRandom);
        orderCode.append(dateTime);
        orderCode.append(random);

        return orderCode.toString();

    }

    /**
     * 获取距离翻倍
     *
     * @author: lig
     * @date: 2023-12-25
     */
    public static BigDecimal gainDoubleDist(Double distDouble) {
        BigDecimal decimal = BigDecimal.valueOf(distDouble);
        decimal = decimal.multiply(BigDecimal.valueOf(2));
        return decimal;
    }

    /**
     * 获取技师预约时间列表
     *
     * @param appointmentTimes
     * @return
     */
    public static List<MemberAppointmentTimeDTO> getOrderTimeList(List<Date> appointmentTimes,LocalDateTime nowDateTime) {
        List<MemberAppointmentTimeDTO> memberAppointmentTimeDTOS = new ArrayList<>();
        //获取空闲时技师可以最早预约的时间
        LocalDateTime availableTime = getLeisureEarliestAvailableAppointmentTime(nowDateTime);
        MemberAppointmentTimeDTO current = new MemberAppointmentTimeDTO();
        MemberAppointmentTimeDTO after = new MemberAppointmentTimeDTO();
        current.setData(availableTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        after.setData(availableTime.plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        //先获取技师目前已经被预约的时间
        List<LocalDateTime> disableTimes = getDisableLocalDateTimes(appointmentTimes);
        //计算从当前时间开始所有符合条件的时间集合
        Date start = toDate(availableTime);
        Date end = toDate(LocalDateTime.of(availableTime.toLocalDate().plusDays(1), LocalTime.MAX));
        List<DateTime> dateRange = DateUtil.rangeToList(start, end, DateField.MINUTE, 30);
        //空闲时技师可以最早预约的时间 与 空闲时技师可以最早预约的时间 计算得出结果
        List<MemberAppointmentTimeListDTO> currentList = new ArrayList<>();
        List<MemberAppointmentTimeListDTO> afterList = new ArrayList<>();
        for (DateTime dateTime : dateRange) {
            LocalDateTime localDateTime = dateTime.toLocalDateTime();
            boolean flag = contains(disableTimes, localDateTime);
            MemberAppointmentTimeListDTO memberAppointmentTimeListDTO = new MemberAppointmentTimeListDTO();
            memberAppointmentTimeListDTO.setIsshow(!flag);
            memberAppointmentTimeListDTO.setTime((localDateTime.getHour() < 10 ? "0" + localDateTime.getHour() : localDateTime.getHour()) + ":" + (localDateTime.getMinute() == 0 ? "00" : localDateTime.getMinute()));
            if (localDateTime.getDayOfMonth() == availableTime.getDayOfMonth()) {
                currentList.add(memberAppointmentTimeListDTO);
            } else {
                afterList.add(memberAppointmentTimeListDTO);
            }
        }
        current.setDatalist(currentList);
        after.setDatalist(afterList);
        memberAppointmentTimeDTOS.add(current);
        memberAppointmentTimeDTOS.add(after);
        return memberAppointmentTimeDTOS;
    }

    private static List<LocalDateTime> getDisableLocalDateTimes(List<Date> appointmentTimes) {
        List<LocalDateTime> localDateTimes = appointmentTimes.stream().map(DateUtil::toLocalDateTime).toList();
        //通过被预约的时间计算出不能被预约的时间
        List<LocalDateTime> disableTimes = new ArrayList<>();
        localDateTimes.forEach(localDateTime -> disableTimes.addAll(getDisableTimeListByAppointTime(localDateTime)));
        return disableTimes;
    }

    /**
     * 获取技师可以预约的集合
     * @param appointmentTimes 技师被预约的时间集合
     * @return 技师可以预约的集合
     */
    public static List<LocalDateTime> getAvailableTimeList(List<Date> appointmentTimes) {
        List<LocalDateTime> result = new ArrayList<>();
        //获取空闲时技师可以最早预约的时间
        LocalDateTime availableTime = getLeisureEarliestAvailableAppointmentTime(LocalDateTime.now());
        //先获取技师目前已经被预约的时间
        List<LocalDateTime> disableTimes = getDisableLocalDateTimes(appointmentTimes);
        //计算从当前时间开始所有符合条件的时间集合
        Date start = toDate(availableTime);
        Date end = toDate(LocalDateTime.of(availableTime.toLocalDate().plusDays(1), LocalTime.MAX));
        List<DateTime> dateRange = DateUtil.rangeToList(start, end, DateField.MINUTE, 30);
        //空闲时技师可以最早预约的时间 与 空闲时技师可以最早预约的时间 计算得出结果
        for (DateTime dateTime : dateRange) {
            LocalDateTime localDateTime = dateTime.toLocalDateTime();
            boolean flag = contains(disableTimes, localDateTime);
            if (!flag) {
                result.add(localDateTime);
            }
        }
        return result;
    }

    public static List<LocalDateTime> getDisableTimeListByAppointTime(LocalDateTime appointTime) {
        List<LocalDateTime> disableTimes = new ArrayList<>();
        disableTimes.add(appointTime.minusMinutes(90));
        disableTimes.add(appointTime.minusMinutes(60));
        disableTimes.add(appointTime.minusMinutes(30));
        disableTimes.add(appointTime);
        disableTimes.add(appointTime.plusMinutes(30));
        disableTimes.add(appointTime.plusMinutes(60));
        disableTimes.add(appointTime.plusMinutes(90));
        return disableTimes;
    }
    /**
     * 获取技师最早可预约时间
     */
    public static LocalDateTime getEarliestAvailableAppointmentTime(List<Date> appointmentTimes) {
        //通过被预约的时间计算出不能被预约的时间
        List<LocalDateTime> disableTimes = getDisableLocalDateTimes(appointmentTimes);
        //获取空闲时技师可以最早预约的时间
        LocalDateTime availableTime = getLeisureEarliestAvailableAppointmentTime(LocalDateTime.now());
        //计算从当前时间开始所有符合条件的时间集合
        Date start = toDate(availableTime);
        Date end = toDate(LocalDateTime.of(availableTime.toLocalDate().plusDays(1), LocalTime.MAX));
        List<DateTime> dateRange = DateUtil.rangeToList(start, end, DateField.MINUTE, 30);
        //空闲时技师可以最早预约的时间 与 空闲时技师可以最早预约的时间 计算得出结果
        AtomicReference<LocalDateTime> result = new AtomicReference<>();
        for (DateTime dateTime : dateRange) {
            boolean flag = contains(disableTimes, dateTime.toLocalDateTime());
            if (!flag) {
                result.set(dateTime.toLocalDateTime());
                break;
            }
        }
        return result.get();
    }

    public static boolean contains(List<LocalDateTime> disableTimes, LocalDateTime localDateTime) {
        AtomicBoolean flag = new AtomicBoolean(false);
        disableTimes.forEach(localDateTime1 -> {
            if (localDateTime1.getYear() == localDateTime.getYear()
                    && localDateTime1.getMonth() == localDateTime.getMonth()
                    && localDateTime1.getDayOfMonth() == localDateTime.getDayOfMonth()
                    && localDateTime1.getHour() == localDateTime.getHour()
                    && localDateTime1.getMinute() == localDateTime.getMinute()) {
                flag.set(true);
            }
        });
        return flag.get();
    }

    public static LocalDateTime getLeisureEarliestAvailableAppointmentTime(LocalDateTime nowLocalDateTime) {
        LocalDateTime now = nowLocalDateTime;
        LocalDateTime current = now.withMinute(30);
        if (now.getMinute() < 30) {
            current = current.plusMinutes(30);
        } else {
            current = current.plusHours(1);
        }
        return current;
    }

    public static void main(String[] args) {
//        LocalDateTime earliest = getLeisureEarliestAvailableAppointmentTime();
//        Date start = toDate(earliest);
//        Date end = toDate(LocalDateTime.of(earliest.toLocalDate().plusDays(1),LocalTime.MAX));
//        List<DateTime> dateRange = DateUtil.rangeToList(start, end, DateField.MINUTE, 30);
//        System.out.println(dateRange);
//        getLeisureEarliestAvailableAppointmentTime();
        getEarliestAvailableAppointmentTime(Lists.newArrayList(toDate(LocalDateTime.of(2023, 12, 29, 10, 30, 0))));
        getOrderTimeList(Lists.newArrayList(toDate(LocalDateTime.of(2023, 12, 26, 20, 0, 0))),null);
    }

    public static Date toDate(LocalDateTime localDateTime) {
        //获取系统默认时区
        ZoneId zoneId = ZoneId.systemDefault();
        //时区的日期和时间
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        //获取时刻
        return Date.from(zonedDateTime.toInstant());
    }

    public static LocalDateTime toLocalDateTime(Date date) {
        return date.toInstant()
                .atZone( ZoneId.systemDefault() )
                .toLocalDateTime();
    }

    /**
     * 构造距离   不允许返回负数
     *
     * @author: lig
     * @date: 2023/12/27
     */
    public static String buildDistance(String distance) {
        String d = "0";
        if (StringUtils.isNotEmpty(distance)) {
            if(Convert.toDouble(distance) < 0){
                return d;
            }else {
                return distance;
            }
        }
        return d;
    }

    /**
     * 构造扩展订单金额总和
     *
     * @author: lig
     * @date: 2023/12/27
     */
    public static Integer buildOrderExtSum(List<OrderExt> orderExtList){
        return Convert.toInt(orderExtList.stream().mapToInt(OrderExt::getOrderPrice).sum(),0);
    }

}
